package com.springboot.demo.class_loader;

import java.net.URL;
import java.net.URLClassLoader;

/**
 * 自定义web加载器
 *
 * @author supu
 * @date 2019-06-25 15:57
 **/
public class CustomWebappClassLoader extends URLClassLoader {
    /**
     * Instance of the SecurityManager installed.
     */
    protected SecurityManager securityManager;


    /**
     * The parent class loader.
     */
    protected ClassLoader parent = null;

    public CustomWebappClassLoader() {
        this(new URL[0], null);
    }


    public CustomWebappClassLoader(ClassLoader parent) {
        this(new URL[0], parent);
    }

    private void init(){
        ClassLoader p = getParent();
        if (p == null) {
            p = getSystemClassLoader();
        }
        this.parent = p;

        securityManager = System.getSecurityManager();
    }

    public CustomWebappClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);

        init();
    }

    public CustomWebappClassLoader(URL[] urls) {
        this(urls, null);
    }

    @Override
    public Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> result = doLoadClass(name);
            if (result == null) {
                throw new ClassNotFoundException(name);
            }
            return resolveIfNecessary(result, resolve);
        }
    }

    private Class<?> doLoadClass(String name) throws ClassNotFoundException {
        checkPackageAccess(name);
        Class<?> result = findClassIgnoringNotFound(name);
        return (result != null) ? result : loadFromParent(name);
    }

    private Class<?> resolveIfNecessary(Class<?> resultClass, boolean resolve) {
        if (resolve) {
            resolveClass(resultClass);
        }
        return (resultClass);
    }

    private Class<?> loadFromParent(String name) {
        if (this.parent == null) {
            return null;
        }
        try {
            return Class.forName(name, false, this.parent);
        }
        catch (ClassNotFoundException ex) {
            return null;
        }
    }

    private Class<?> findClassIgnoringNotFound(String name) {
        try {
            return findClass(name);
        }
        catch (ClassNotFoundException ex) {
            return null;
        }
    }

    private void checkPackageAccess(String name) throws ClassNotFoundException {
        if (this.securityManager != null && name.lastIndexOf('.') >= 0) {
            try {
                this.securityManager
                        .checkPackageAccess(name.substring(0, name.lastIndexOf('.')));
            }
            catch (SecurityException ex) {
                throw new ClassNotFoundException("Security Violation, attempt to use "
                        + "Restricted Class: " + name, ex);
            }
        }
    }
}
